/*
 * host.c
 *
 *  Created on: 11 mars 2012
 *      Author: mfred
 */

#define frand() ((double) rand() / (RAND_MAX+1.0))

#import <stdlib.h>
#import <stdio.h>

static const int N = 16;

struct boule{
	int r_int;
	int r_ext;
	float indices[16];
	float evaluation;
	float evaluation_corrigee;
};

struct boule* initialisation(struct boule b_initiale)
{
	struct boule *tab = malloc(sizeof(struct boule)*N);
	int i;
	for (i = 0 ; i < N ; i++) {
		int j;
		for (j = 1 ; j < b_initiale.r_int ; j++) {
			tab[i].indices[j] = 0;
		}
		int k;
		for (k = b_initiale.r_int+1 ; k < b_initiale.r_ext ; k++) {
			tab[i].indices[k] = b_initiale.indices[k];
		}
		tab[i].r_int = b_initiale.r_int;
		tab[i].r_ext = b_initiale.r_ext;
		tab[i].evaluation = b_initiale.evaluation;
	}

	return tab;
}

struct boule* mutation(struct boule *tabAnciennes)
{
	srand(time(NULL));
	struct boule *tabNouvelles = malloc(sizeof(struct boule) * N);
	int couche_mutee;
	float facteur_de_mutation;
	int i;
	for(i = 0 ; i<N ; i++){
		couche_mutee = rand() % tabAnciennes[i].r_ext;
		facteur_de_mutation = frand()+.5;
		tabNouvelles[i].r_int = tabAnciennes[i].r_int;
		tabNouvelles[i].r_ext = tabAnciennes[i].r_ext;
		int j;
		for (j = 0 ; j < tabAnciennes[i].r_int ; j++) {
			tabNouvelles[i].indices[j] = 0;
		}
		for (j = tabAnciennes[i].r_int + 1 ; j < tabAnciennes[i].r_ext ; j++) {
			tabNouvelles[i].indices[j] = tabAnciennes[i].indices[j];
		}
		tabNouvelles[i].indices[couche_mutee] *= facteur_de_mutation;
		tabNouvelles[i].evaluation = 0;
	}
	return tabNouvelles;
}

void evaluation(struct boule *tabNouvelles)
{
	// Chargez sub1 puis sub2 (Cuda)

	// Evaluation test :somme des indices de refraction
	int i;
	for (i = 0 ; i < N ; i++) {
		int j;
		float ev = 0;
		for (j = 0 ; j < tabNouvelles[i].r_ext ; j++) {
			ev += tabNouvelles[i].indices[j];
		}
		tabNouvelles[i].evaluation = ev;
	}
}

int compare_configurations(void const *a, void const *b) {
	// Resultat positif ssi b est meilleure que a
	struct boule const *ap = a;
	struct boule const *bp = b;
	float eval_a = ap->evaluation_corrigee;
	float eval_b = bp->evaluation_corrigee;
	return 2*(eval_b > eval_a)-1;
}

struct boule* triEtSelection(struct boule* tabAnciennes, struct boule* tabNouvelles) {

	// Premiere etape : on multiplie par un facteur aleatoire compris entre 0.8 et 1 les evaluations de chaque configuration,
	// afin de laisser une chance de survie aux configurations imparfaites

	struct boule configurations[2*N];
	int i;
	float facteurA;
	float facteurN;
	for (i = 0 ; i < N ; i++) {
		facteurA = 1-frand()*0.2;
		facteurN = 1-frand()*0.2;

		configurations[2*i].r_int = tabAnciennes[i].r_int;
		configurations[2*i].r_ext = tabAnciennes[i].r_ext;
		int j;
		for (j = tabAnciennes[i].r_int+1 ; j < tabAnciennes[i].r_ext ; j++){
			configurations[2*i].indices[j] = tabAnciennes[i].indices[j];
		}
		configurations[2*i].evaluation_corrigee = tabAnciennes[i].evaluation * facteurA;
		configurations[2*i].evaluation = tabAnciennes[i].evaluation;

		configurations[2*i+1].r_int = tabNouvelles[i].r_int;
		configurations[2*i+1].r_ext = tabNouvelles[i].r_ext;

		for (j = tabNouvelles[i].r_int+1 ; j < tabNouvelles[i].r_ext ; j++){
			configurations[2*i+1].indices[j] = tabNouvelles[i].indices[j];
		}
		configurations[2*i+1].evaluation_corrigee = tabNouvelles[i].evaluation * facteurN;
		configurations[2*i+1].evaluation = tabNouvelles[i].evaluation;
	}

	// Deuxieme etape : trier les configurations par rapport, par ordre decroissant de la valeur d'evaluation_corrigee
	qsort(configurations, 2*N, sizeof(struct boule), compare_configurations);

	// Troisieme etape : on ne conserve que les meilleures configurations
	struct boule *selectionnees = malloc(sizeof(struct boule) * N);
	for (i = 0 ; i < N ; i++) {
		selectionnees[i].r_int = configurations[i].r_int;
		selectionnees[i].r_ext = configurations[i].r_ext;
		int j;
		for (j = configurations[i].r_int + 1 ; j < configurations[i].r_ext ; j++) {
			selectionnees[i].indices[j] = configurations[i].indices[j];
		}
		selectionnees[i].evaluation = configurations[i].evaluation;
		selectionnees[i].evaluation_corrigee = configurations[i].evaluation_corrigee;
	}

	return selectionnees;
}


int main(int argc, char *argv[]) {

	struct boule start;
	start.r_int = 0;
	start.r_ext = 10;
	int i;
	for (i = 0 ; i < 10 ; i++) {
		start.indices[i] = 2;
	}
	start.evaluation = (start.r_ext-1)*2;
	struct boule *pool = initialisation(start);
	printf("Config initiale : \n");
	for (i = 0 ; i < N ; i++){
		printf("Configuration %i : evaluee a %f\n", i, pool[i].evaluation);
	}
	//	printf("Rayon int : %i \n", pool[0].r_int);
	//	printf("Rayon ext : %i \n", pool[0].r_ext);
	//	printf("Couche 0 : %f \n", pool[0].indices[0]);
	//	printf("Couche 1 : %f \n", pool[0].indices[1]);
	//	printf("Couche 2 : %f \n", pool[0].indices[2]);
	//	printf("Couche 3 : %f \n", pool[0].indices[3]);
	//	printf("Couche 4 : %f \n", pool[0].indices[4]);
	//	printf("Couche 5 : %f \n", pool[0].indices[5]);
	//	printf("Couche 6 : %f \n", pool[0].indices[6]);
	//	printf("Couche 7 : %f \n", pool[0].indices[7]);
	//	printf("Couche 8 : %f \n", pool[0].indices[8]);
	//	printf("Couche 9 : %f \n", pool[0].indices[9]);
	//	printf("Evaluation : %f \n", pool[0].evaluation);

	struct boule *pool_mute = mutation(pool);
	evaluation(pool_mute);
	printf("Apres mutation : \n");
	for (i = 0 ; i < N ; i++){
		printf("Configuration %i : evaluee a %f \n", i, pool_mute[i].evaluation);
	}
	//	printf("Rayon int : %i \n", pool_mute[0].r_int);
	//	printf("Rayon ext : %i \n", pool_mute[0].r_ext);
	//	printf("Couche 0 : %f \n", pool_mute[0].indices[0]);
	//	printf("Couche 1 : %f \n", pool_mute[0].indices[1]);
	//	printf("Couche 2 : %f \n", pool_mute[0].indices[2]);
	//	printf("Couche 3 : %f \n", pool_mute[0].indices[3]);
	//	printf("Couche 4 : %f \n", pool_mute[0].indices[4]);
	//	printf("Couche 5 : %f \n", pool_mute[0].indices[5]);
	//	printf("Couche 6 : %f \n", pool_mute[0].indices[6]);
	//	printf("Couche 7 : %f \n", pool_mute[0].indices[7]);
	//	printf("Couche 8 : %f \n", pool_mute[0].indices[8]);
	//	printf("Couche 9 : %f \n", pool_mute[0].indices[9]);
	//	printf("Evaluation : %f \n", pool_mute[0].evaluation);

	struct boule *pool_selectionne = triEtSelection(pool, pool_mute);
	printf("Apres selection : \n");
	for (i = 0 ; i < N ; i++){
		printf("Configuration %i : evaluee a %f (corrigee a %f) \n", i, pool_selectionne[i].evaluation, pool_selectionne[i].evaluation_corrigee);
	}
	return 0;
}
